package com.mjk.common.tools.scheduled;


import com.mjk.common.tools.logger.BizLogger;
import org.springframework.data.util.Pair;
import org.springframework.scheduling.config.ScheduledTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.config.TriggerTask;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;

/**
 * 动态任务 上下文 
 * @author Administrator
 *
 */
public class DynamicScheduledContent {
	/**
     * IDSTaskInfo和真实任务的关联关系
     * <p>
     * <task_id, <Task, <Scheduled, Semaphore>>>
     */
    private final Map<String, Pair<DynamicScheduledModel, Pair<ScheduledTask, Semaphore>>> scheduleMap = new ConcurrentHashMap<>();

    private final ScheduledTaskRegistrar taskRegistrar;

    public DynamicScheduledContent(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        this.taskRegistrar = scheduledTaskRegistrar;
    }

    /**
     * 注册任务
     * @param taskInfo 任务信息
     * @param triggerTask 任务的触发规则
     */
    public void checkTask(final DynamicScheduledModel taskInfo, final TriggerTask triggerTask) {
        final String taskId = taskInfo.getId();
        if (scheduleMap.containsKey(taskId)) {
            if (taskInfo.isValid()) {
                final DynamicScheduledModel oldTaskInfo = scheduleMap.get(taskId).getFirst();
                if(taskInfo.isChange(oldTaskInfo)) {
	                BizLogger.info("IDynamicScheduled will restart because task change, taskId: "+taskId );
		            cancelTask(taskId);
		            registerTask(taskInfo, triggerTask);
                }
            } else {
                BizLogger.info("IDynamicScheduled will cancelTask because task not valid, taskId: "+taskId );
                cancelTask(taskId);
            }
        } else {
            if (taskInfo.isValid()) {
            	BizLogger.info("IDynamicScheduled will registerTask, taskId: "+taskId);
                registerTask(taskInfo, triggerTask);
            }
        }
    }

    /**
     * 获取 Semaphore，确保任务不会被多个线程同时执行
     */
    public Semaphore getSemaphore(final String taskId) {
        return this.scheduleMap.get(taskId).getSecond().getSecond();
    }

    private void registerTask(final DynamicScheduledModel taskInfo, final TriggerTask triggerTask) {
        final ScheduledTask latestTask = taskRegistrar.scheduleTriggerTask(triggerTask);
        if (latestTask != null) {
            this.scheduleMap.put(taskInfo.getId(), Pair.of(taskInfo, Pair.of(latestTask, new Semaphore(1))));
        }
    }

    private void cancelTask(final String taskId) {
        final Pair<DynamicScheduledModel, Pair<ScheduledTask, Semaphore>> pair = this.scheduleMap.remove(taskId);
        if (pair != null) {
            pair.getSecond().getFirst().cancel();
        }
    }
}
